package com.moss.cloud.base.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moss.cloud.base.api.model.from.BaseFrom;
import com.moss.cloud.base.api.model.from.OAuthClientFrom;
import com.moss.cloud.base.api.model.param.ClientPageParam;
import com.moss.cloud.base.api.model.vo.ClientVO;
import com.moss.cloud.base.biz.mapper.SysClientMapper;
import com.moss.cloud.base.biz.model.OauthClientDetails;
import com.moss.cloud.base.biz.model.SysClient;
import com.moss.cloud.base.biz.service.IOauthClientDetailsService;
import com.moss.cloud.base.biz.service.ISysClientService;
import com.moss.cloud.common.base.utils.PageUtil;
import com.moss.cloud.common.core.constant.Constant;
import com.moss.cloud.common.core.constant.RoleCode;
import com.moss.cloud.common.core.exception.SystemErrorType;
import com.moss.cloud.common.core.utils.AESUtil;
import com.moss.cloud.common.core.utils.BooleanHandel;
import com.moss.cloud.common.core.utils.MD5Util;
import com.moss.cloud.common.security.annotation.RequiresRole;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 客户端管理业务实现
 *
 * @author 瑾年
 * @date 2023年11月19日
 */
@Slf4j
@Service
public class SysClientServiceImpl extends ServiceImpl<SysClientMapper, SysClient> implements ISysClientService {

    private final IOauthClientDetailsService oauthClientDetailsService;

    public SysClientServiceImpl(IOauthClientDetailsService oauthClientDetailsService) {
        this.oauthClientDetailsService = oauthClientDetailsService;
    }

    /**
     * 客户端分页查询
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<ClientVO> clientPage(ClientPageParam pageParam) {
        Page<ClientVO> page = PageUtil.createPage(pageParam.getCurrent(), pageParam.getSize());
        IPage<ClientVO> clientVOPage = this.baseMapper.clientPage(page, pageParam);
        BooleanHandel.isTrue(CollectionUtils.isNotEmpty(clientVOPage.getRecords())).trueHandle(() ->
                clientVOPage.getRecords().forEach(item -> {
            item.setScopeList(Arrays.stream(item.getScope().split(","))
                    .collect(Collectors.toList()));
            item.setAuthorizedGrantTypesList(Arrays.stream(item.getAuthorizedGrantTypes().split(","))
                    .collect(Collectors.toList()));
        }));
        return clientVOPage;
    }

    /**
     * 新增保存客户端
     *
     * @param clientFrom
     * @return
     */
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveClient(OAuthClientFrom clientFrom) {
        String clientId = MD5Util.genClientId();
        String clientSecret = MD5Util.genClientSecret();
        OauthClientDetails oauthClientDetails = new OauthClientDetails();
        BeanUtils.copyProperties(clientFrom, oauthClientDetails);
        oauthClientDetails.setClientId(clientId);
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        oauthClientDetails.setClientSecret(passwordEncoder.encode(clientSecret));
        oauthClientDetails.setScope(String.join(",", clientFrom.getScopeList()));
        oauthClientDetails.setAuthorizedGrantTypes(String.join(",", clientFrom.getAuthorizedGrantTypesList()));
        boolean flag = oauthClientDetailsService.save(oauthClientDetails);
        SysClient sysClient = new SysClient();
        BeanUtils.copyProperties(clientFrom, sysClient);
        sysClient.setClientId(clientId);
        sysClient.setClientSecret(AESUtil.aesEncrypt(clientSecret,Constant.KEY));
        return flag ? this.save(sysClient) : Boolean.FALSE;
    }

    /**
     * 修改客户端
     *
     * @param clientFrom
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateClient(OAuthClientFrom clientFrom) {
        BooleanHandel.trueThrow(Objects.isNull(clientFrom.getId())).throwMessage(SystemErrorType.PRIMARY_KEY);
        SysClient sysClient = this.checkClient(clientFrom.getId());
        OauthClientDetails oauthClientDetails = new OauthClientDetails();
        BeanUtils.copyProperties(clientFrom, oauthClientDetails);
        oauthClientDetails.setClientId(sysClient.getClientId());
        oauthClientDetails.setScope(String.join(",", clientFrom.getScopeList()));
        oauthClientDetails.setAuthorizedGrantTypes(String.join(",", clientFrom.getAuthorizedGrantTypesList()));
        boolean flag = oauthClientDetailsService.update(oauthClientDetails, new QueryWrapper<OauthClientDetails>().lambda()
                .eq(OauthClientDetails::getClientId, sysClient.getClientId()));
        SysClient client = new SysClient();
        BeanUtils.copyProperties(clientFrom, sysClient);
        return flag ? this.updateById(client) : Boolean.FALSE;
    }

    /**
     * 验证当前数据是否存在并返回数据
     *
     * @param primaryKey
     * @return
     */
    private SysClient checkClient(Long primaryKey) {
        SysClient sysClient = this.getById(primaryKey);
        BooleanHandel.trueThrow(Objects.isNull(sysClient)).throwMessage(SystemErrorType.DATE_EMPTY);
        return sysClient;
    }

    /**
     * 删除客户端
     *
     * @param baseFrom
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeClient(BaseFrom baseFrom) {
        SysClient sysClient = this.checkClient(baseFrom.getId());
        boolean flag = oauthClientDetailsService.remove(new QueryWrapper<OauthClientDetails>().lambda()
                .eq(OauthClientDetails::getClientId, sysClient.getClientId()));
        return flag ? this.removeById(baseFrom.getId()) : Boolean.FALSE;
    }

    /**
     * 查看客户端秘钥
     *
     * @param baseFrom
     * @return
     */
    @Override
    @SneakyThrows
    @RequiresRole(codes = {RoleCode.SYSTEM_ADMIN})
    public String viewClientSecret(BaseFrom baseFrom) {
        SysClient sysClient = this.checkClient(baseFrom.getId());
        return AESUtil.aesDecrypt(sysClient.getClientSecret(), Constant.KEY);
    }

    /**
     * 重置客户端秘钥
     *
     * @param baseFrom
     * @return
     */
    @Override
    @SneakyThrows
    @RequiresRole(codes = {RoleCode.SYSTEM_ADMIN})
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetSecret(BaseFrom baseFrom) {
        SysClient sysClient = this.checkClient(baseFrom.getId());
        String clientSecret = MD5Util.genClientSecret();
        OauthClientDetails oauthClientDetails = new OauthClientDetails();
        oauthClientDetails.setClientId(sysClient.getClientId());
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        oauthClientDetails.setClientSecret(passwordEncoder.encode(clientSecret));
        boolean flag = oauthClientDetailsService.update(oauthClientDetails, new QueryWrapper<OauthClientDetails>().lambda()
                .eq(OauthClientDetails::getClientId, sysClient.getClientId()));
        SysClient client = new SysClient();
        client.setId(baseFrom.getId());
        client.setClientSecret(AESUtil.aesEncrypt(clientSecret, Constant.KEY));
        return flag ? this.updateById(client) : Boolean.FALSE;
    }
}
